package com.shigu.weixin.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.opentae.data.mall.beans.MallWallet;
import com.opentae.data.mall.beans.ManagerMallUser;
import com.opentae.data.mall.beans.UserWxInfo;
import com.opentae.data.mall.interfaces.MallWalletMapper;
import com.opentae.data.mall.interfaces.ManagerMallUserMapper;
import com.opentae.data.mall.interfaces.TransMallMapper;
import com.opentae.data.mall.interfaces.UserWxInfoMapper;
import com.shigu.weixin.exceptions.UtilsException;
import com.shigu.weixin.util.HttpUtils;
import com.shigu.weixin.util.XcxPayConfig;
import com.shigu.weixin.vo.SnsOauth2Access_tokenGet;
import com.shigu.weixin.vo.WebToken;
import com.shigu.weixin.vo.XcxAuthVo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.sword.wechat4j.api.WechatClient;
import org.sword.wechat4j.api.request.Cgi_binTokenGet;
import org.sword.wechat4j.api.response.Token;

import java.io.IOException;
import java.util.Date;


@Service
public class WxUserService {
    @Autowired
    ManagerMallUserMapper managerMallUserMapper;
    @Autowired
    MallWalletMapper mallWalletMapper;
    @Autowired
    TransMallMapper transMallMapper;
    @Autowired
    UserWxInfoMapper userWxInfoMapper;

    private static final Logger logger = LoggerFactory.getLogger(WxUserService.class);

    private final String host = "https://api.weixin.qq.com";
    private final String token = "cailifukeji";
    //小程序秘钥
    @Value("${xcx.secret}")
    private String xcxSecret;
    //公众号秘钥
    @Value("${wechat.appid}")
    private String wxAppId;
    @Value("${wechat.appsecret}")
    private String wxSecret;

    /**
     * @description 获取token
     * @author 郭尔
     * @date 2019-06-19 10:07
     */
    @Cacheable(value = "wx_token_cach", key = "#APP_ID+'_'+#APP_SECRET")
    public Token getSystemToken(String APP_ID, String APP_SECRET) throws IOException {
        WechatClient client = new WechatClient(host, APP_ID, APP_SECRET, token);
        Cgi_binTokenGet cgi_binTokenGet = new Cgi_binTokenGet();
        cgi_binTokenGet.setAppid(APP_ID);
        cgi_binTokenGet.setSecret(APP_SECRET);
        return client.execute(cgi_binTokenGet);
    }

    /**
     * @description 公众号获取unionId
     * @author 郭尔
     * @date 2019-06-19 10:09
     */
    public String getGzhUnionId(String gzhOpenId) throws IOException {
        String accessToken = getSystemToken(wxAppId, wxSecret).getAccess_token();
        String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID";
        requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", gzhOpenId);
        String data = HttpUtils.get(requestUrl);
        if (StringUtils.isBlank(data)) {
            return null;
        }
        JSONObject object = JSON.parseObject(data);
        //1 表示关注 0表示未关注
        if (object.getInteger("subscribe") == 1) {
            return object.getString("unionid");
        } else {
            //未关注无法获取unionId
            return null;
        }
    }

    /**
     * @description code换取用户openid he
     * @author 郭尔
     * @date 2019/1/16 16:26
     */
    public XcxAuthVo xcxAuth(String code) throws Exception {
        XcxPayConfig config = new XcxPayConfig();
        String url = host + "/sns/jscode2session?appid=" + config.getAppID() + "&secret=" + xcxSecret + "&js_code=" + code +
                "&grant_type=authorization_code";
        String data = HttpUtils.get(url);
        if (StringUtils.isBlank(data)) {
            throw new UtilsException("获取用户信息失败");
        }
        JSONObject object = JSON.parseObject(data);
        XcxAuthVo vo = new XcxAuthVo();
        vo.setOpenid(object.getString("openid"));
        vo.setSessionKey(object.getString("session_key"));
        return vo;
    }

    /**
     * todo userType 枚举在webserver 里 。。。，
     *
     * @description 将openid存表
     * @author 郭尔
     * @date 2019/1/16 16:28
     */
    public Long wxAppLogin(String openIid, String headUrl, String nick, String unionId) {

//        ManagerMallUser user=managerMallUserMapper.selUserByUnionId(unionId);
        UserWxInfo info = userWxInfoMapper.selByUnionId(unionId);
        if (info == null) {
            ManagerMallUser user = new ManagerMallUser();
            user.setCreateTime(new Date());
            user.setUserType(1);
            managerMallUserMapper.insertSelective(user);

            info = new UserWxInfo();
            info.setMallUserId(user.getMallUserId());
            info.setUnionId(unionId);
            info.setWxNick(nick);
            info.setWxHeadUrl(headUrl);
            info.setXcxOpeniid(openIid);
            userWxInfoMapper.insertSelective(info);

            MallWallet wallet = new MallWallet();
            wallet.setUserId(info.getMallUserId());
            mallWalletMapper.insertSelective(wallet);

        } else {
            //原用户头像.昵称更新
            info.setUnionId(unionId);
            info.setWxNick(nick);
            info.setWxHeadUrl(headUrl);
            info.setXcxOpeniid(openIid);
            userWxInfoMapper.updateByPrimaryKeySelective(info);

        }
        return info.getMallUserId();
    }

    /**
     * @return 返回小程序的用户id，让外部进行操作
     * @description 绑定用户
     * @author 郭尔
     * @date 2019-05-07 13:38
     */
    public synchronized Long appBindWx(Long mallUserId, String unionId, String wxNick, String openId, String avatarUrl) throws UtilsException {
        //根据unionId 查询用户
        UserWxInfo wxInfo = userWxInfoMapper.selectByPrimaryKey(mallUserId);
        if (wxInfo != null && wxInfo.getAppOpeniid() != null) {
            throw new UtilsException("已绑定过微信了");
        }

        UserWxInfo info = new UserWxInfo();
        UserWxInfo oldWxInfo = userWxInfoMapper.selByUnionId(unionId);
        if (oldWxInfo == null) {
            info.setMallUserId(mallUserId);
            info.setWxHeadUrl(avatarUrl);
            info.setUnionId(unionId);
            info.setWxNick(wxNick);
            info.setAppOpeniid(openId);
            userWxInfoMapper.insertSelective(info);
        } else {
            //绑定用户
            if (oldWxInfo.getAppOpeniid() != null) {
                //已绑定的用户
                throw new UtilsException("绑定失败，该微信已被其他用户绑定");
            }
            ManagerMallUser appUser = new ManagerMallUser();
            appUser.setMallUserId(mallUserId);

            //数据转移到appUser上
            ManagerMallUser user = managerMallUserMapper.selectFieldsByPrimaryKey(oldWxInfo.getMallUserId(), "have_cost");
            appUser.setHaveCost(user.getHaveCost() + appUser.getHaveCost());
            managerMallUserMapper.updateByPrimaryKeySelective(appUser);

            info.setUnionId(unionId);
            info.setWxNick(wxNick);
            info.setWxHeadUrl(avatarUrl);
            info.setAppOpeniid(openId);
            info.setGzhOpeniid(oldWxInfo.getGzhOpeniid());
            info.setGzhPayOpeniid(oldWxInfo.getGzhPayOpeniid());
            info.setXcxOpeniid(oldWxInfo.getXcxOpeniid());
            info.setWxHeadUrl(oldWxInfo.getWxHeadUrl());
            info.setMallUserId(appUser.getMallUserId());

            userWxInfoMapper.insertSelective(info);
            //返回小程序的用户id
            return user.getMallUserId();
        }

        return null;
    }

    /**
     * 静默登陆
     *
     * @param code
     * @return
     * @throws IOException
     */
    public WebToken mkWebToken(String code) {
        WechatClient client = new WechatClient(host, wxAppId, wxSecret, token);
        SnsOauth2Access_tokenGet tokenGet = new SnsOauth2Access_tokenGet();
        tokenGet.setCode(code);
        try {
            return client.execute(tokenGet);
        } catch (Exception e) {
            logger.error("hasFollow error! code:" + code, e);
            return null;
        }
    }

    /**
     * @description 公众号号 用户
     * @author 郭尔
     * @date 2019-05-16 9:59
     */
    @Deprecated
    public Long addOpeniidToUser(String openId) {
        //查询是否存在该用户
        UserWxInfo userWxInfo = userWxInfoMapper.selByGzhOpeniid(openId);
        if (userWxInfo != null) {
            return userWxInfo.getMallUserId();
        }
        ManagerMallUser user = new ManagerMallUser();
        user.setCreateTime(new Date());
        user.setUserType(3);
        managerMallUserMapper.insertSelective(user);
        // 用于user表的主键做为该表的主键
        UserWxInfo info = new UserWxInfo();
        info.setMallUserId(user.getMallUserId());
        info.setGzhOpeniid(openId);
        info.setGzhPayOpeniid(openId);
        userWxInfoMapper.insertSelective(info);

        return user.getMallUserId();
    }

    /**
     * @param openId  公众号的 openid
     * @param unionid 用户唯一标识，未关注公众号的为null
     * @return 用户的id
     * @description 公众号微信登录
     * @author 郭尔
     * @date 2019-06-19 12:50
     *
     * =======================================
     * unionid 可能为空.所以在未关注公众号的情况下 ，
     * 即使 app 已经绑定用户，仍然无法绑定。
     * (关注后可以正常获取，需要用户清除微信的缓存)
     */
    public Long bindGzh(String openId, String unionid) {
        //查询用户
        UserWxInfo gzhInfo = userWxInfoMapper.selByGzhOpeniid(openId);
        UserWxInfo appInfo = null;
        if (StringUtils.isNotBlank(unionid)) {
            appInfo = userWxInfoMapper.selByUnionId(unionid);
        }

        if (appInfo != null) {
            appInfo.setGzhOpeniid(openId);
            appInfo.setGzhPayOpeniid(openId);
            //更新
            userWxInfoMapper.updateByPrimaryKeySelective(appInfo);
        }

        //已登录过公众号
        if (gzhInfo != null) {
            //其他地方绑定了微信
            if (gzhInfo.getUnionId() == null && appInfo != null) {

               /* 没关注过的情况下的登录了，在这之后app注册并绑定了微信
                 删除原公众号的,这里没有更新数据,所以在下次查询gzh的时候，
                 返回null，会在下面更新保存到完整的数据
                */
                userWxInfoMapper.deleteByPrimaryKey(gzhInfo.getMallUserId());
                managerMallUserMapper.deleteByPrimaryKey(gzhInfo.getMallUserId());
                return appInfo.getMallUserId();
                //返回的一个是app的用户id
            }
          /*  如果 unionid !=null，2个账号会是同一个
             如果 unioonid == null 但是 appinfo ==null，说明没有app绑定过
             都返回gzh 的 userid 就可以了
            */
            return gzhInfo.getMallUserId();
        }
        //工作号没有登录过，但是存在app绑定过
        if (appInfo != null) {
            return appInfo.getMallUserId();
        }

        ManagerMallUser user = new ManagerMallUser();
        user.setCreateTime(new Date());
        user.setUserType(3);
        managerMallUserMapper.insertSelective(user);
        // 用于user表的主键做为该表的主键
        UserWxInfo info = new UserWxInfo();
        info.setUnionId(unionid);
        info.setMallUserId(user.getMallUserId());
        info.setGzhOpeniid(openId);
        info.setGzhPayOpeniid(openId);
        userWxInfoMapper.insertSelective(info);

        return user.getMallUserId();

    }
}
